import threading
import time
import logging
from datetime import datetime
from src.models.models import db, DownloadQueue, DownloadTask, get_beijing_time

# 配置日志
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)

# 队列处理线程
queue_processor_thread = None
queue_processor_running = False
queue_processor_lock = threading.Lock()

# 全局变量来存储 Flask 应用实例
_app_instance = None

def queue_processor_worker():
    """队列处理工作线程"""
    global queue_processor_running
    
    logger.info("下载队列处理器启动")
    
    while queue_processor_running:
        try:
            # 确保 _app_instance 已经被设置
            if _app_instance is None:
                logger.error("Flask 应用实例未设置，队列处理器无法运行。")
                time.sleep(10)  # 避免无限循环
                continue

            with _app_instance.app_context():  # 推入应用程序上下文
                # 获取所有待处理的队列项目（按优先级排序）
                with queue_processor_lock:
                    queue_items = DownloadQueue.query.filter_by(status='queued')\
                                                   .order_by(DownloadQueue.priority.desc(), DownloadQueue.created_at.asc())\
                                                   .all()  # 处理所有待处理的任务
                
                if queue_items:
                    # 在函数内部导入download_task避免循环导入
                    from src.services.downloader import download_task
                    
                    for queue_item in queue_items:
                        try:
                            # 更新队列状态
                            queue_item.status = 'processing'
                            queue_item.updated_at = get_beijing_time()
                            db.session.commit()
                            
                            # 获取对应的下载任务
                            task = DownloadTask.query.get(queue_item.task_id)
                            if not task:
                                queue_item.status = 'failed'
                                queue_item.error_message = '下载任务不存在'
                                queue_item.updated_at = get_beijing_time()
                                db.session.commit()
                                continue
                            
                            # 执行下载任务
                            result = download_task(task)
                            
                            # 更新队列状态
                            if result['success']:
                                queue_item.status = 'completed'
                            else:
                                queue_item.status = 'failed'
                                queue_item.error_message = result['message']
                                queue_item.retry_count += 1
                                
                                # 如果未达到最大重试次数，重新排队
                                if queue_item.retry_count < queue_item.max_retries:
                                    queue_item.status = 'queued'
                            
                            queue_item.updated_at = get_beijing_time()
                            db.session.commit()
                            
                            logger.info(f"处理队列项目 {queue_item.id} 完成，状态: {queue_item.status}")
                            
                        except Exception as e:
                            logger.error(f"处理队列项目 {queue_item.id} 失败: {str(e)}")
                            try:
                                queue_item.status = 'failed'
                                queue_item.error_message = str(e)
                                queue_item.updated_at = get_beijing_time()
                                db.session.commit()
                            except:
                                pass
                else:
                    # 没有待处理的任务，等待一段时间
                    time.sleep(5)
                    
        except Exception as e:
            logger.error(f"队列处理器执行出错: {str(e)}")
            time.sleep(10)  # 出错后等待10秒再继续
    
    logger.info("下载队列处理器已停止")

def start_queue_processor():
    """启动队列处理器"""
    global queue_processor_thread, queue_processor_running
    
    with queue_processor_lock:
        if queue_processor_running:
            logger.info("队列处理器已在运行中")
            return True
        
        try:
            queue_processor_running = True
            queue_processor_thread = threading.Thread(target=queue_processor_worker, daemon=True)
            queue_processor_thread.start()
            
            logger.info("队列处理器已启动")
            return True
            
        except Exception as e:
            logger.error(f"启动队列处理器失败: {str(e)}")
            queue_processor_running = False
            return False

def stop_queue_processor():
    """停止队列处理器"""
    global queue_processor_thread, queue_processor_running
    
    with queue_processor_lock:
        if not queue_processor_running:
            logger.info("队列处理器未在运行")
            return True
        
        try:
            queue_processor_running = False
            
            # 等待线程结束
            if queue_processor_thread and queue_processor_thread.is_alive():
                queue_processor_thread.join(timeout=5)
            
            queue_processor_thread = None
            
            logger.info("队列处理器已停止")
            return True
            
        except Exception as e:
            logger.error(f"停止队列处理器失败: {str(e)}")
            return False

def is_queue_processor_running():
    """检查队列处理器是否在运行"""
    return queue_processor_running and queue_processor_thread and queue_processor_thread.is_alive()

def get_queue_status():
    """获取队列状态"""
    try:
        # 确保有应用上下文
        if _app_instance is None:
            return {
                'processor_running': False,
                'queued': 0,
                'processing': 0,
                'completed': 0,
                'failed': 0,
                'total': 0
            }
        
        with _app_instance.app_context():
            queued_count = DownloadQueue.query.filter_by(status='queued').count()
            processing_count = DownloadQueue.query.filter_by(status='processing').count()
            completed_count = DownloadQueue.query.filter_by(status='completed').count()
            failed_count = DownloadQueue.query.filter_by(status='failed').count()
            
            return {
                'processor_running': is_queue_processor_running(),
                'queued': queued_count,
                'processing': processing_count,
                'completed': completed_count,
                'failed': failed_count,
                'total': queued_count + processing_count + completed_count + failed_count
            }
    except Exception as e:
        logger.error(f"获取队列状态失败: {str(e)}")
        return {
            'processor_running': False,
            'queued': 0,
            'processing': 0,
            'completed': 0,
            'failed': 0,
            'total': 0
        }

def init_queue_processor(app_instance):
    """初始化队列处理器"""
    global _app_instance
    _app_instance = app_instance
    try:
        start_queue_processor()
        logger.info("队列处理器初始化完成")
    except Exception as e:
        logger.error(f"初始化队列处理器失败: {str(e)}")

def process_queue_immediately():
    """立即处理队列中的任务"""
    try:
        # 确保有应用上下文
        if _app_instance is None:
            logger.error("Flask 应用实例未设置，无法处理队列")
            return 0
        
        with _app_instance.app_context():
            with queue_processor_lock:
                # 获取所有待处理的队列项目（按优先级排序）
                queue_items = DownloadQueue.query.filter_by(status='queued')\
                                               .order_by(DownloadQueue.priority.desc(), DownloadQueue.created_at.asc())\
                                               .all()  # 处理所有待处理的任务
                
                processed_count = 0
                
                if queue_items:
                    # 在函数内部导入download_task避免循环导入
                    from src.services.downloader import download_task
                
                for queue_item in queue_items:
                    try:
                        # 更新队列状态
                        queue_item.status = 'processing'
                        queue_item.updated_at = get_beijing_time()
                        db.session.commit()
                        
                        # 获取对应的下载任务
                        task = DownloadTask.query.get(queue_item.task_id)
                        if not task:
                            queue_item.status = 'failed'
                            queue_item.error_message = '下载任务不存在'
                            queue_item.updated_at = get_beijing_time()
                            db.session.commit()
                            continue
                        
                        # 执行下载任务
                        result = download_task(task)
                        
                        # 更新队列状态
                        if result['success']:
                            queue_item.status = 'completed'
                        else:
                            queue_item.status = 'failed'
                            queue_item.error_message = result['message']
                            queue_item.retry_count += 1
                            
                            # 如果未达到最大重试次数，重新排队
                            if queue_item.retry_count < queue_item.max_retries:
                                queue_item.status = 'queued'
                        
                        queue_item.updated_at = get_beijing_time()
                        db.session.commit()
                        
                        processed_count += 1
                        logger.info(f"立即处理队列项目 {queue_item.id} 完成，状态: {queue_item.status}")
                        
                    except Exception as e:
                        logger.error(f"立即处理队列项目 {queue_item.id} 失败: {str(e)}")
                        try:
                            queue_item.status = 'failed'
                            queue_item.error_message = str(e)
                            queue_item.updated_at = get_beijing_time()
                            db.session.commit()
                        except:
                            pass
                
                return processed_count
                
    except Exception as e:
        logger.error(f"立即处理队列失败: {str(e)}")
        return 0 